import { Injector } from "./utils/Injector";
import { MathUtils } from "./utils/MathUtils";
import { storage } from "../module/storage/Storage";
import { timer } from "../module/timer/Timer";
import { app } from "./typings/global";
import { publisher } from "../module/publisher/PublisherManager";
import { net } from "../module/net/NetManager";
import { eventCenter } from "./event/EventDispatcher";
import { viewManager } from "../module/view/ViewManager";

(globalThis as any)['app'] = (globalThis as any)['app'] || {
    version: "1.0.0",
    storage: storage,
    timer: timer,
    App: App,
    publisher: publisher,
    net: net,
    eventCenter: eventCenter,
    viewManager: viewManager,
};


/**
 * 版本号
 */

enum APPStorageKey {
    //安装时间
    INSTALL_TIME_KEY = "INSTALL_TIME_KEY",
}

export interface IApplication {
    launch(): void;

    onShow(call: () => void, caller?: any): void;

    offShow(call: () => void, caller?: any): void;

    onHide(call: () => void, caller?: any): void;

    offHide(call: () => void, caller?: any): void;
}

/**
 * 框架接口，由各个引擎实现，处理框架启动等逻辑
 */
export class Application {
    static KEY = "app.Application";
    private _installTime: number = 0;
    private _launchTime: number = 0;

    /**
     * 启动框架
     * @param {{injects?:any[]}} data 启动数据
     * @returns 
     */
    launch(data?: { injects?: any[] }): void {
        if (this._launchTime) {
            return;
        }
        MathUtils.seed = Math.random();
        this._launchTime = Date.now();
        this._injects(data && data.injects);
        this.impl.launch();
        app.timer.enable();

        let isFirstLaunch: boolean = this.isFirstLaunch;
        console.log(`App Launch Done. isFirstLaunch:${isFirstLaunch}`);
    }

    /**
     * 注入组件
     * @param injects 
     */
    protected _injects(injects: any[]) {
        injects && injects.forEach((clazz, key) => {
            Injector.inject(clazz['KEY'], clazz);
        })
    }

    /**
     * 当前用户是否是登录后第一次启动
     */
    get isFirstLaunchOfThisUser(): boolean {
        let value: number = app.storage.getUValue<number>(APPStorageKey.INSTALL_TIME_KEY, 0);
        if (!value) {
            app.storage.setUValue(APPStorageKey.INSTALL_TIME_KEY, this._launchTime);
        }
        return !value || value == this._launchTime;
    }

    /**
     * 是否是第一次启动
     */
    get isFirstLaunch(): boolean {
        return this.installTime == this._launchTime;
    }

    /**
     * 当前的启动时间戳（毫秒）
     */
    get launchTime(): number {
        return this._launchTime;
    }

    /**
     * 当前启动时长（毫秒）
     */
    get durationOfLaunch(): number {
        return Date.now() - this._launchTime;
    }

    /**
     * 安装后的时长(毫秒)
     */
    get durationOfInstall(): number {
        return Date.now() - this.installTime;
    }

    /**
     * 安装时间（第一次启动时间戳）（毫秒）
     */
    get installTime(): number {
        let value: number = this._installTime || app.storage.getGValue<number>(APPStorageKey.INSTALL_TIME_KEY, 0);
        if (!value) {
            this._installTime = this._launchTime;
            app.storage.setGValue(APPStorageKey.INSTALL_TIME_KEY, this._launchTime);
        } else {
            this._installTime = value;
        }
        return this._installTime;
    }

    /**
     * 安装后的天数
     */
    get daysInstall(): number {
        const millisecondsOfDay = 24 * 60 * 60 * 1000;
        return Math.floor(this.durationOfInstall / millisecondsOfDay);
    }

    /**
     * 安装后的小时数
     */
    get hoursInstall(): number {
        const millisecondsOfHour = 60 * 60 * 1000;
        return Math.floor(this.durationOfInstall / millisecondsOfHour);
    }

    /**
     * 安装后的分钟数
     */
    get minutesInstall(): number {
        const millisecondsOfMinute = 60 * 1000;
        return Math.floor(this.durationOfInstall / millisecondsOfMinute);
    }

    onShow(call: (...args: any[]) => void, caller?: any): void {
        this.impl.onShow(call, caller);
    }

    offShow(call: (...args: any[]) => void, caller?: any): void {
        this.impl.offShow(call, caller);
    }

    onHide(call: (...args: any[]) => void, caller?: any): void {
        this.impl.onHide(call, caller);
    }

    offHide(call: (...args: any[]) => void, caller?: any): void {
        this.impl.offHide(call, caller);
    }

    private _impl: IApplication;
    private get impl(): IApplication {
        if (this._impl == null) {
            this._impl = Injector.getInject(Application.KEY);
        }
        if (this._impl == null) {
            throw new Error(Application.KEY + "未注入！");
        }
        return this._impl;
    }
}

/**
 * 框架接口
 */
export var App: Application = new Application();
